package org.xlp.queue;

/**
 * Description: 用数组实现的循环队列
 * <br/>date: 2025/3/28
 *
 * @version 1.0
 * @author: xlp
 */
public class CircularQueue<E> {
    /**
     * 存储队列数据
     */
    private E[] data;

    /**
     * 队列首指针
     */
    private int front;

    /**
     * 队列尾指针
     */
    private int rear;

    /**
     * 队列大小
     */
    private int size;

    /**
     * 构造函数
     * @param size 队列大小
     */
    @SuppressWarnings("unchecked")
    public CircularQueue(int size){
        // 预留一个空位置
        this.size = size + 1;
        this.data = (E[]) new Object[this.size];
    }

    /**
     * 判断循环队列是否已满
     * @return 返回：true：已满，false：未满
     */
    public boolean isFull(){
        return (rear + 1) % size == front;
    }

    /**
     * 向循环队列尾部添加元素
     * @param e 要添加的元素
     * @return true：添加成功，false：队列已满添加失败
     */
    public boolean push(E e){
        if (isFull()) return false;
        rear = (rear + 1) % size;
        data[rear] = e;
        return true;
    }

    /**
     * 弹出队首的一个元素
     * @return 返回弹出队首的那个元素
     * @throws EmptyQueueException 假如队列为空，操作该方法，则抛出该异常
     */
    public E pop() throws EmptyQueueException{
        if (isEmpty()) throw new EmptyQueueException("队列为空，操作失败！");
        front = (front + 1) % size;
        E e = data[front];
        // 弹出的位置设置为空，以便垃圾回收
        data[front] = null;
        return e;
    }

    /**
     * 获取队首的一个元素（不移除对首元素）
     * @return 返回队首的那个元素
     * @throws EmptyQueueException 假如队列为空，操作该方法，则抛出该异常
     */
    public E peek() throws EmptyQueueException{
        if (isEmpty()) throw new EmptyQueueException("队列为空，操作失败！");
        return data[(front + 1) % size];
    }

    /**
     * 判断队列是否为空
     * @return 返回true：为空，false：非空
     */
    public boolean isEmpty(){
        return rear == front;
    }
}
